//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008-2010, Shane J. M. Liesegang
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright 
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the copyright holder nor the names of any 
//       contributors may be used to endorse or promote products derived from 
//       this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "StringUtil.h"
#include "Log.h"
#include "Vector2.h"

///The on-screen console: handles input, history, and executing commands
/** 
 * This abstract base class contains everything you need to create your own
 *  console that responds to user input. The base class handles displaying and
 *  hiding the console, taking input, and recording command history. 
 * 
 * To make a console, your subclass needs to implement the Execute function
 *  (which gets called with a string whenever the user enters input) and the
 *  GetCompletions function, which returns a StringList of potential 
 *  auto-complete values. 
 * 
 * Most of this is academic, as you'll probably use the Lua console, which
 *  has already implemented all of this for you.
 * 
 * There's also a TestConsole implementation that does nothing but echo your
 *  commands back at you. It's the default console, so if you ever see its 
 *  prompt (\c ::>), you know something has gone wrong with loading the 
 *  real console. 
 */
class Console
{
public:
        /**
         * The default constructor makes sure our console font (Inconsolata at)
         *  18 points) is registered with the text rendering system. 
         */
        Console();
        
        /**
         * Does nothing in the base class, but you gotta have it
         */
        virtual ~Console();

        /**
         * Override of the Renderable::Render function that actually draws the console,
         *  if necessary.
         */
        void Render();
        
        /**
         * Oddly enough, doesn't do anything. All the changes happen at user
         *  input instead of in the update loop. 
         * 
         * @param dt
         */
        void Update( float /*dt*/ );

        /**
         * Turns the console on (or off), which makes it get drawn in the render loop and 
         *  steals keyboard input from the rest of the game. 
         * 
         * @param bEnable If true, the Console is activate; if false, it's deactivated. 
         */
        void Enable( bool bEnable = true );
        
        /**
         * Whether the Console is currently being displayed and accepting input right now. 
         * 
         * @return True if it's enabled, false if it's not
         */
        bool IsEnabled() {return _enabled;}
        
        /**
         * Adds the given key to the Console's current input string. Should only be 
         *  called by the input handling functions. 
         * 
         * @param key The numeric representation of the key
         * @return Whether or not the key was added to the input string (false if
         *   the Console is currently disabled or that was the key which toggled it.)
         */
        bool GetInput(int key);
        
        /**
         * Handles special input like Enter, Escape, arrow keys, etc. Again, this 
         *  should only be called by the input handling functions. 
         * 
         * @param key The numeric representation of the special key
         * @return Whether or not the input was accepted by the Console (false if
         *   the Console is currently disabled.)
         */
        bool GetSpecialInputDown( int key );
        
        /**
         * Switches the console from on to off, or from off to on. 
         */
        void ToggleConsole();
        
        /**
         * Lets you know what key is set to toggle the Console. (Hard-coded to
         *  \c '`' at the moment.)
         * 
         * @return The toggle console key
         */
        unsigned char GetToggleConsoleKey()     {return '`';}
        
        /**
         * Writes a string to the log area of the console. Used internally by 
         *  Console implementations to display the results of commands. 
         * 
         * @param output The string to be appended to the log area. 
         */
        void WriteToOutput(String output);
        
        /**
         * Set the prompt characters that users will see at the beginning of their
         *  input line. Some consoles like to change this to reflect their current
         *  state. 
         * 
         * @param prompt The new prompt string
         */
        void SetPrompt(String prompt);

        /**
         * Get the width of tabs when output to this console.
         */
        const unsigned int GetTabWidth();

        /**
         * Get the width of tabs when output to this console. Defaults to 8.
         * 
         * @param newTabWidth The desired tab width in spaces
         */
        void SetTabWidth(unsigned int newTabWidth);
        
        /**
         * Replaces the current input string with a value from the input history. 
         * 
         * @param byVal The offset from the current history. Negative numbers will
         *   go back in the history, positive ones will go forward. 
         */
        void AdvanceInputHistory( int byVal );
        
        /**
         * Replaces the input string with the current top auto-complete choice. 
         */
        void AcceptAutocomplete();

        /**
         * Process the current input string, work whatever magic is appropriate. 
         *
         * Pure virtual function; must be implemented in the subclass.
         * 
         * @param input The string to process in the Console
         */
        virtual void Execute(String input) = 0;
        
        /**
         * Gets a set of strings that are potential auto-complete matches for the
         *  current input. 
         * 
         * Pure virtual function; must be implemented in the subclass. 
         * 
         * @param input The input string to try and match. 
         * @return The list of potential matches
         */
        virtual StringList GetCompletions(String input) = 0;

protected:
        bool IsTextKey(unsigned char key);
        void AcceptCurrentInput();
        String _currentInput;
        StringList _inputHistory;
        int _inputHistoryPos;
        String _prompt;
        StringList _buffer;
        String _unsplitBuffer;
        float _lineHeight;
        StringList _autoCompleteList;
        int _cursorPos;
        unsigned int _tabWidth;
        
private:
        void RefreshAutoCompletes();
        float _cursorDispTime;
        bool _bCursorDisp;
        
        bool _enabled;
};

///An example Console implementation
/**
 * A degenerate case of a Console; does nothing but echo the user input back
 *  into the screen log. 
 */ 
class TestConsole : public Console
{
public:
        /**
         * Sets up the prompt (\c ::>); 
         */
        TestConsole()
        {
                SetPrompt("::>");
        }

        /**
         * Echos the input right back out. 
         * 
         * @param input The string to echo
         */
        virtual void Execute(String input) { WriteToOutput("Test Console Echo: " + input); }
        
        /**
         * Returns an empty StringList. 
         * 
         * @param input The input to be ignored
         * @return An empty list
         */
        virtual StringList GetCompletions(String input) { return StringList(); }
};